package com.zz.ecommerce.togatherDeclareMgr.qdc.service;

import com.zz.bundles.cache.dict.DictTag;
import com.zz.ecommerce.common.CommonDao;
import com.zz.ecommerce.common.bean.qdc.db.TContainerListQdc;
import com.zz.ecommerce.common.bean.qdc.db.TDeclformHeadQdc;
import com.zz.ecommerce.common.bean.qdc.db.TGoodsListQdc;
import com.zz.ecommerce.common.constants.TableConstants;
import com.zz.ecommerce.togatherDeclareMgr.common.bean.TCargo;
import com.zz.ecommerce.togatherDeclareMgr.common.bean.TContainers;
import com.zz.ecommerce.togatherDeclareMgr.common.bean.TEntryInfo;
import com.zz.ecommerce.togatherDeclareMgr.common.bean.TWorksheet;
import com.zz.ecommerce.togatherDeclareMgr.common.bean.TWorksheetContainer;
import com.zz.ecommerce.togatherDeclareMgr.common.bean.TWorksheetGoods;
import com.zz.ecommerce.togatherDeclareMgr.common.dao.TCargoDao;
import com.zz.ecommerce.togatherDeclareMgr.common.dao.TContainerDao;
import com.zz.ecommerce.togatherDeclareMgr.common.dao.TEntryInfoDao;
import com.zz.ecommerce.togatherDeclareMgr.qdc.dao.QDTDeclareContainersDao;
import com.zz.ecommerce.togatherDeclareMgr.qdc.dao.QDTDeclareFormGoodsDao;
import com.zz.ecommerce.togatherDeclareMgr.qdc.dao.QDTDeclareFormHeadDao;
import com.zz.ecommerce.user.UserInfo;
import com.zz.ecommerce.utils.BeanMapUtill;
import com.zz.ecommerce.utils.DateUtil;
import com.zz.ecommerce.utils.SessionUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 清单生成报关单
 * <p/>
 * 清单表头同一收发货人、同一运输方式、同一运抵国、同一出境口岸，
 * <p/>
 * 以及清单表体同一10位海关商品编码、同一申报计量单位、同一币制规则进行归并
 * <p/>
 * <p/>
 * 不满足规则的就只生成单条报关单
 * <p/>
 * <p/>
 * Created by rocky.liuguo on 2016/4/7.
 */
@Service
public class QDCustDeclarationGenerateService {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final static String PREX = "cargo.";

    @Autowired
    private QDTDeclareFormHeadDao qdtDeclareFormHeadDao;

    @Autowired
    private QDTDeclareFormGoodsDao qdtDeclareFormGoodsDao;

    @Autowired
    private QDTDeclareContainersDao qdtDeclareContainersDao;

    @Autowired
    private TEntryInfoDao entryInfoDao;

    @Autowired
    private TCargoDao cargoDao;

    @Autowired
    private TContainerDao tContainerDao;

    @Autowired
    private CommonDao commonDao;

    public String getLongSeq() {
        return cargoDao.getLongSeq("SEQ_COMMON");
    }

    public String getELongSeq() {
        return cargoDao.getELongSeq("SEQ_COMMON");
    }

    /**
     * 生成海关的报关单
     *
     * @param idList
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    @Transactional(readOnly = false)
    public void toDeclareCust(List<String> idList)
        throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        List<TDeclformHeadQdc> declarationHeadList = new ArrayList<>();
        for (String id : idList) {
            if (StringUtils.isEmpty(id)) {
                continue;
            }
            TDeclformHeadQdc tDeclformHeadQdc = new TDeclformHeadQdc();
            tDeclformHeadQdc.setId(id);
            tDeclformHeadQdc = qdtDeclareFormHeadDao.query(TableConstants.T_DECLFORM_HEAD_QDC, tDeclformHeadQdc);

            if (null == tDeclformHeadQdc) {
                throw new RuntimeException("查询不到流水号:[" + id + "]的申报清单信息");
            }

            if (StringUtils.isNotEmpty(tDeclformHeadQdc.getRelateDeclCustId())) {
                throw new RuntimeException("申报单流水号:[" + id + "]的申报单已经生成报关单，不能重复生成");
            }

            declarationHeadList.add(tDeclformHeadQdc);
        }

        //根据表头合并的条件，重新分组申报清单表头对象,生成报关单时，只使用集合中的第一条
        Map<String, List<TDeclformHeadQdc>> warpDeclformHeadList = warpDeclformHeadList(declarationHeadList);

        //2.合并商品列表 集装箱信息列表
        Map<String, List<?>> declarationBodyMap = mergeGoodsAndContainers(warpDeclformHeadList);
        try {
            for (String key : warpDeclformHeadList.keySet()) {
                List<TDeclformHeadQdc> tDeclformHeadQdcList = warpDeclformHeadList.get(key);
                TDeclformHeadQdc tDeclformHeadQdc = tDeclformHeadQdcList.get(0);
                logger.debug("-----------------tDeclformHeadQdc-------------->{}", tDeclformHeadQdc);
                //3.保存综合表报关单表头
                TWorksheet tWorksheet = saveWorksheetHead(tDeclformHeadQdc);
                if (tWorksheet != null) {
                    //4.保存综合表报关单货物信息
                    //如果当前货物列表总数大于50条，分为多个报关单生成
                    List<TGoodsListQdc> tGoodsListQdcs = (List<TGoodsListQdc>)
                        declarationBodyMap.get(tDeclformHeadQdc.getId()).get(0);

                    List<TGoodsListQdc> actualTGoodsListQdcs = new ArrayList<>();

                    int totalPages = 0;
                    int pageSize = 50;
                    if (tGoodsListQdcs != null) {
                        if (tGoodsListQdcs.size() > 50) {
                            int count = tGoodsListQdcs.size() / pageSize;
                            if (tGoodsListQdcs.size() % pageSize > 0) {
                                totalPages = count + 1;
                            } else {
                                totalPages = count;
                            }
                            logger.debug("货物信息数量为{},大于50条，只生成{}条报关单", tGoodsListQdcs.size(), totalPages);
                            //先保存前50条货物信息
                            for (int i = 0; i < pageSize; i++) {
                                actualTGoodsListQdcs.add(tGoodsListQdcs.get(i));

                            }
                            logger.debug("保存前50条的货物信息---->{}", actualTGoodsListQdcs);
                            //3 保存货物信息
                            saveWorksheetGoods(tWorksheet.getSheetnoZ(), actualTGoodsListQdcs);
                            //剩下的货物信息需要先生成报关单，在将货物信息关联该报关单进行保存
                            for (int pageNo = 1; pageNo < totalPages; pageNo++) {
                                actualTGoodsListQdcs = new ArrayList<>();
                                for (int currentCount = 0; currentCount < pageSize; currentCount++) {
                                    if (pageNo * pageSize + currentCount >= tGoodsListQdcs.size()) {
                                        break;
                                    }
                                    actualTGoodsListQdcs.add(tGoodsListQdcs.get(pageNo * pageSize + currentCount));
                                }
                                logger.debug("保存从{}条到{}条的货物信息,生成一条报关单---->{}", pageNo * pageSize,
                                             pageNo * pageSize + pageSize - 1,
                                             actualTGoodsListQdcs);
                                //保存表头信息
                                tWorksheet = saveWorksheetHead(tDeclformHeadQdc);
                                //3 保存货物信息
                                saveWorksheetGoods(tWorksheet.getSheetnoZ(), actualTGoodsListQdcs);
                            }
                        } else {
                            logger.debug("货物信息数量小于50条，只生成一条报关单");
                            //3 保存货物信息
                            saveWorksheetGoods(tWorksheet.getSheetnoZ(), actualTGoodsListQdcs);
                        }
                    }
                    //4.保存综合表报关单集装箱信息
                    saveWorksheetContainers(tWorksheet.getSheetnoZ(), (List<TContainerListQdc>) declarationBodyMap.get(
                        tDeclformHeadQdc
                            .getId()).get(
                        1));
                    //5.更新申报单关联字段
                    for (TDeclformHeadQdc head : declarationHeadList) {
                        updateDeclareFormHead(head.getId(), tWorksheet.getSheetnoZ());
                    }
                }

                //                //3.保存报关单表头
                //                TEntryInfo entryInfo = saveHead(tDeclformHeadQdc);
                //                if (entryInfo != null) {
                //                    //4.保存报关单货物信息
                //                    saveGoods(entryInfo.getConIndx(), (List<TGoodsListQdc>) declarationBodyMap.get(
                //                        tDeclformHeadQdc.getId())
                //                        .get
                //                            (0));
                //
                //                    //4.保存报关单集装箱信息
                //                    saveContainers(entryInfo.getIndx(), (List<TContainerListQdc>)
                //                        declarationBodyMap.get(
                //                            tDeclformHeadQdc
                //                                .getId()).get(
                //                            1));
                //                    //5.更新申报单关联字段
                //                    for (TDeclformHeadQdc head : declarationHeadList) {
                //                        updateDeclareFormHead(head.getId(), entryInfo.getIndx());
                //                    }
                //                }
            }
        } catch (Exception e) {
            logger.error("toDeclareCust------>Exception", e);
            throw new RuntimeException("生成报关单失败!" + e.getMessage());
        }

    }


    /**
     * 总署：同一收发货人、同一运输方式、同一运抵国、同一出境口岸
     *
     * @param declarationHeadList
     * @return
     */
    private Map<String, List<TDeclformHeadQdc>> warpDeclformHeadList(List<TDeclformHeadQdc> declarationHeadList) {
        if (CollectionUtils.isEmpty(declarationHeadList)) {
            logger.error("生成报关单的清单数据为空.");
            return null;
        }
        //以表头合并条件为综合key，保存满足合并条件的清单表头对象
        Map<String, List<TDeclformHeadQdc>> declformHeadMap = new HashMap<>();

        List<TDeclformHeadQdc> tDeclformHeadQdcList = null;
        logger.debug("待生成报关单的清单数量----->{}", declarationHeadList.size());
        for (TDeclformHeadQdc tDeclformHeadQdc : declarationHeadList) {
            String ownerCertId = tDeclformHeadQdc.getOwnerCertId();//收件人证件号
            String iePort = tDeclformHeadQdc.getIePort();//进出境口岸
            String trafMode = tDeclformHeadQdc.getTrafMode();//运输方式
            String tradeCount = tDeclformHeadQdc.getTradeCount();//启运国/运抵国
            String tradeCode = tDeclformHeadQdc.getTradeCode();//经营单位
            logger.debug("iePort----->{},trafMode----->{},tradeCount----->{},ownerCertId----->{}", iePort, trafMode,
                         tradeCount, ownerCertId);
            StringBuilder keySb = new StringBuilder(1024);
            keySb.append(iePort).append("_").append(trafMode).append("_").append(tradeCount).append("_").append
                (ownerCertId);
            if (declformHeadMap.containsKey(keySb.toString())) {
                tDeclformHeadQdcList = declformHeadMap.get(keySb.toString());
            } else {
                tDeclformHeadQdcList = new ArrayList<>();
            }
            tDeclformHeadQdcList.add(tDeclformHeadQdc);
            declformHeadMap.put(keySb.toString(), tDeclformHeadQdcList);
        }
        logger.debug("归类合并处理以后,待生成报关单的清单数量----->{}", declformHeadMap.size());
        return declformHeadMap;
    }

    /**
     * 查询清单对应的货物信息，并对满足条件的货物信息进行归类
     * <p/>
     * 同一10位海关商品编码、同一申报计量单位、同一币制规则进行归并
     * <p/>
     * 关联ID=货物信息（满足条件的合并）
     *
     * @param declformHeadMap
     * @return
     */
    private Map<String, List<?>> mergeGoodsAndContainers(Map<String, List<TDeclformHeadQdc>> declformHeadMap) {
        if (null == declformHeadMap) {
            logger.error("清单信息为空，无法进行商品和集装箱的归类合并计算处理。");
            return null;
        }
        //最终返回的结果集，申报清单集合第一条：List<对应的商品信息列表（合并后 ）,集装箱信息列表（汇总）>
        Map<String, List<?>> declformBodyMap = new HashMap<>();

        //同一10位海关商品编码、同一申报计量单位、同一币制规则进行归并
        Map<String, TGoodsListQdc> goodsListQdcMap = new HashMap<>();
        for (String key : declformHeadMap.keySet()) {
            List<TDeclformHeadQdc> tDeclformHeadQdcList = declformHeadMap.get(key);//归类合并后的清单信息列表
            if (CollectionUtils.isEmpty(tDeclformHeadQdcList)) {
                continue;
            }
            //该清单集合对应的所有的商品信息汇总集合
            List<TGoodsListQdc> tGoodsListQdcs = new ArrayList<>();

            //该清单集合对应的所有的集装箱信息汇总集合
            List<TContainerListQdc> tContainerListQdcs = new ArrayList<>();

            //该清单集合对应的所有的集装箱信息+商品信息 汇总集合
            List declformBodyList = new ArrayList<>();

            String declformBodyKey = tDeclformHeadQdcList.get(0).getId();
            //遍历所有的清单信息，获取到对应的商品信息、集装箱信息。并进行合并归类
            for (TDeclformHeadQdc tDeclformHeadQdc : tDeclformHeadQdcList) {

                //查询该清单对应的商品信息
                TGoodsListQdc goods = new TGoodsListQdc();
                goods.setRelatedId(tDeclformHeadQdc.getId());
                List<TGoodsListQdc> curGoodsList = qdtDeclareFormGoodsDao.queryAll(TableConstants.T_GOODS_LIST_QDC,
                                                                                   goods, "");
                logger.debug("清单={}------>共计货物信息数量为------->{}", tDeclformHeadQdc.getId(), curGoodsList.size());
                //遍历货物信息
                for (TGoodsListQdc tGoodsListQdc : curGoodsList) {
                    String hsCode = tGoodsListQdc.getCodeTs();//海关商品编码
                    String gUnit = tGoodsListQdc.getgUnit();//申报计量单位
                    //                    String unit1 = tGoodsListQdc.getUnit1();//法定计量单位
                    String currCode = tGoodsListQdc.getCurrCode();//币值

                    BigDecimal gnum = tGoodsListQdc.getgNum();
                    BigDecimal totalPrice = tGoodsListQdc.getTotalPrice();
                    BigDecimal qty1 = tGoodsListQdc.getQty1();
                    BigDecimal taxPayment = tGoodsListQdc.getTaxPayment();

                    StringBuilder keySb = new StringBuilder(1024);
                    keySb.append(hsCode).append("_").append(gUnit).append("_").append
                        (currCode);
                    if (goodsListQdcMap.containsKey(keySb.toString())) {
                        //对货物信息进行合并   数量	G_NUM   总价	TOTAL_PRICE   法定数量	QTY_1  税款 TAX_PAYMENT
                        TGoodsListQdc exitTGoodsListQdc = goodsListQdcMap.get(keySb.toString());
                        if (exitTGoodsListQdc != null) {
                            if (null == exitTGoodsListQdc.getgNum()) {
                                exitTGoodsListQdc.setgNum(gnum);
                            } else {
                                exitTGoodsListQdc.setgNum(exitTGoodsListQdc.getgNum().add(gnum));
                            }
                            if (null == exitTGoodsListQdc.getTotalPrice()) {
                                exitTGoodsListQdc.setTotalPrice(totalPrice);
                            } else {
                                exitTGoodsListQdc.setTotalPrice(exitTGoodsListQdc.getTotalPrice().add(totalPrice));
                            }
                            if (null == exitTGoodsListQdc.getQty1()) {
                                exitTGoodsListQdc.setQty1(qty1);
                            } else {
                                exitTGoodsListQdc.setQty1(exitTGoodsListQdc.getQty1().add(qty1));
                            }
                            if (null == exitTGoodsListQdc.getTaxPayment()) {
                                exitTGoodsListQdc.setTaxPayment(qty1);
                            } else {
                                exitTGoodsListQdc.setTaxPayment(exitTGoodsListQdc.getTaxPayment().add(taxPayment));
                            }
                            //                            tGoodsListQdcs.add(exitTGoodsListQdc);
                            goodsListQdcMap.put(keySb.toString(), exitTGoodsListQdc);
                        }
                    } else {
                        //                        tGoodsListQdcs.add(tGoodsListQdc);
                        goodsListQdcMap.put(keySb.toString(), tGoodsListQdc);
                    }
                }

                //查询对应的集装箱信息
                TContainerListQdc containerListQdc = new TContainerListQdc();
                containerListQdc.setReleatedId(tDeclformHeadQdc.getId());
                List<TContainerListQdc> containerListQdcList = qdtDeclareContainersDao.queryAll(
                    TableConstants.T_CONTAINER_LIST_QDC,
                    containerListQdc, "");

                tContainerListQdcs.addAll(containerListQdcList);
            }

            //转换为实际需要保存的货物信息列表
            for (String goodsKey : goodsListQdcMap.keySet()) {
                tGoodsListQdcs.add(goodsListQdcMap.get(goodsKey));
            }

            logger.debug("合并归类后货物信息数量为------->{}", tGoodsListQdcs.size());
            declformBodyList.add(tGoodsListQdcs);
            logger.debug("合并归类后集装箱信息数量为------->{}", tContainerListQdcs.size());
            declformBodyList.add(tContainerListQdcs);

            //保存该清单对应的商品信息 +集装箱信息
            declformBodyMap.put(declformBodyKey, declformBodyList);
        }
        return declformBodyMap;
    }

    /**
     * 保存报关单表头 到综合表中 和T_ENTRYINFO
     *
     * @param declareHead
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    private TWorksheet saveWorksheetHead(TDeclformHeadQdc declareHead)
        throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        if (null == declareHead) {
            logger.error("保存表头信息失败，表头信息为空.");
            return null;
        }
        Map<String, String> mapper = new HashMap<>();
        //报关流水号
        mapper.put("entryNoC", "");
        //报/转关类型
        mapper.put("dectransidC", "");
        mapper.put("dectranscnC", "");
        //报关单类型
        mapper.put("custypecoC", "");
        mapper.put("custypecnC", "");

        //申报地海关
        mapper.put("declarecustomscoC", "declPort");
        mapper.put("declarecustomsC", "");

        //统一编号
        mapper.put("unientryidC", "");

        //预录入编号
        mapper.put("preentryidC", "");

        //海关编号
        mapper.put("entryidC", "");

        //备案号
        mapper.put("manualnoC", "");
        //合同协议号
        mapper.put("contractnoC", "");
        //出口口岸
        mapper.put("portcoC", "");
        mapper.put("portcnC", "");

        //出口日期
        mapper.put("exImDaC", "ieDate");
        //申报日期
        mapper.put("declaredaC", "");
        //经营单位
        mapper.put("operatoridC", "tradeCode");
        mapper.put("operatorcnC", "tradeName");
        //运输方式
        mapper.put("transportcoC", "trafMode");
        mapper.put("transportcnC", "");
        //发货单位
        mapper.put("ownercoC", "");
        mapper.put("ownernaC", "");
        //运输工具名称
        mapper.put("conveyanceC", "trafName");
        //申报单位
        mapper.put("declareidC", "agentCode");
        mapper.put("declarecnC", "agentName");
        //航次号
        mapper.put("voyagenoC", "voyageNo");
        //提运单号
        mapper.put("billnoC", "billNo");
        //监管方式
        mapper.put("tradecoC", "");
        mapper.put("tradecnC", "");
        //纳税单位
        mapper.put("paytaxcoC", "");
        mapper.put("paytaxcnC", "");
        //许可证号
        mapper.put("licencenoC", "");
        //运抵国(地区)
        mapper.put("nationcoC", "tradeCount");
        mapper.put("nationcocnC", "");
        //指运港
        mapper.put("havencoC", "");
        mapper.put("havencnC", "");
        //成交方式
        mapper.put("tradetermscoC", "");
        mapper.put("tradetermscnC", "");

        //运费
        mapper.put("carriagesyC", "");
        mapper.put("carriagesysyC", "");
        mapper.put("carriagesmC", "");
        mapper.put("carriagecrC", "");
        mapper.put("carriagecrcnC", "");

        //征免性质
        mapper.put("dutycoC", "");
        mapper.put("dutycnC", "");

        //保费
        mapper.put("insurancesyC", "");
        mapper.put("insurancesysyC", "");
        mapper.put("insurancesmC", "");
        mapper.put("insurancecrC", "");
        mapper.put("insurancecrcnC", "");

        //结汇方式
        mapper.put("paymentcoC", "");
        mapper.put("paymentcnC", "");

        //杂费
        mapper.put("incidentalsyC", "");
        mapper.put("incidentalsysyC", "");
        mapper.put("incidentalsmC", "");
        mapper.put("incidentalcrC", "");
        mapper.put("incidentalcrcnC", "");

        //件数
        mapper.put("piecesC", "packNum");
        //包装种类
        mapper.put("packagecoC", "");
        mapper.put("packagecnC", "");
        //毛重
        mapper.put("grossC", "grossWeight"); //TODO 分为多个报关单时，货物列表中没有重量，无法获取到每一个报关单的实际重量
        //净重
        mapper.put("suttleC", "");
        //境内货源地
        mapper.put("regioncoC", "");
        mapper.put("regioncnC", "");
        //备注
        mapper.put("remarkC", "");

        TWorksheet tWorksheet = new TWorksheet();
        BeanMapUtill.populate(mapper, declareHead, tWorksheet);

        tWorksheet.setSheetnoZ(getLongSeq());
        tWorksheet.setIndxC(getLongSeq());
        tWorksheet.setIndxZ(getLongSeq());
        tWorksheet.setConIndxC(tWorksheet.getSheetnoZ());
        String ieFlag = declareHead.getIeFlag();
        tWorksheet.setEntrytyC(ieFlag);
        tWorksheet.setTradecoC("9610");
        tWorksheet.setBusinesstypeZ(ieFlag);

        String entrytycn = "";
        if ("I".equals(ieFlag)) {
            entrytycn = "进口";
        } else if ("E".equals(ieFlag)) {
            entrytycn = "出口";
        }
        tWorksheet.setEntrytycnC(entrytycn);
        tWorksheet.setCreatetimeC(DateUtil.nowTime());
        tWorksheet.setMakedateZ(DateUtil.nowTime());
        tWorksheet.setDeclarefactorZ("2");//只报关
        tWorksheet.setDeclarecnC("0");//一般报关单
        tWorksheet.setDeclarecustomsC(declareHead.getDeclPort());//申报地海关

        //        HttpServletRequest request =
        //            ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //        UserInfo user = SessionUtil.getUserInfo(request.getSession());
        UserInfo user = new UserInfo();
        tWorksheet.setAgentcoC(user.getCompanyName());
        tWorksheet.setMakerC(user.getLogName());
        tWorksheet.setMakerZ(user.getLogName());
        tWorksheet.setMakernameZ(user.getLogName());
        tWorksheet.setStatusC("0");
        tWorksheet.setOrganizationIdZ(user.getCompanyId());//组织机构记录保存的序列号
        tWorksheet.setOrganizationcodeC(user.getCompanyId());//组织机构记录保存的序列号

        logger.debug("save T_WORKSHEET------>{}", tWorksheet);
        commonDao.insert(PREX + "T_WORKSHEET", tWorksheet);
        logger.debug("save T_WORKSHEET------>end");

        logger.debug("save T_WORKSHEET------>{}", tWorksheet.toTEntryInfo());
        commonDao.insert(PREX + "T_ENTRYINFO", tWorksheet.toTEntryInfo());
        logger.debug("save T_WORKSHEET------>end");

        return tWorksheet;
    }

    /**
     * 保存货物信息列表 到综合表中 T_WORKSHEET_GOODS 和 T_CARGO
     *
     * @param conIndx
     * @param declarationGoodsList
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    private void saveWorksheetGoods(String conIndx, List<TGoodsListQdc> declarationGoodsList)
        throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        if (StringUtils.isEmpty(conIndx)) {
            logger.error("保存货物信息失败，没有对应的表头信息");
            return;
        }
        if (CollectionUtils.isEmpty(declarationGoodsList)) {
            logger.warn("保存货物信息失败，需要保存的货物信息为空");
            return;
        }
        int i = 0;
        for (TGoodsListQdc goods : declarationGoodsList) {
            Map<String, String> goodsMapper = new HashMap<>();

            goodsMapper.put("modelC", "gModel"); //商品型号
            goodsMapper.put("memoC", "");
            goodsMapper.put("cargotaxcoC", "codeTs");//hscode
            goodsMapper.put("legalsmC", "qty1");//法定数量
            goodsMapper.put("menorizesignC", "");
            goodsMapper.put("nationnameC", "");
            goodsMapper.put("bargaintoC", "");
            goodsMapper.put("bargainsmC", "gNum");//数量
            goodsMapper.put("cargocnC", "gName");///商品名称
            goodsMapper.put("quaIndxC", "");
            goodsMapper.put("bargaincrcnC", "");
            goodsMapper.put("seconduncnC", "");
            goodsMapper.put("cargoenC", "");
            goodsMapper.put("legalunC", "unit1");//法定单位
            goodsMapper.put("legaluncnC", "");
            goodsMapper.put("levycoC", "dutyMode");//征免方式
            goodsMapper.put("codeTC", "");
            goodsMapper.put("codeSC", "");
            goodsMapper.put("secondsmC", "");
            //            goodsMapper.put("serialnoC", i++ + "");//序号
            goodsMapper.put("nationcoC", "originCountry");//原产国/目的国
            goodsMapper.put("manualsnC", "");
            goodsMapper.put("purposecoC", "");
            goodsMapper.put("secondunC", "");
            goodsMapper.put("levycocnC", "");
            goodsMapper.put("bargainunC", "");
            goodsMapper.put("nationcocnC", "");
            goodsMapper.put("bargainunnameC", "");
            goodsMapper.put("purposecocnC", "");
            goodsMapper.put("bargainuncnC", "");
            goodsMapper.put("manufacturerC", "");
            goodsMapper.put("bargainpriceC", "price");//单价
            goodsMapper.put("enyIndxC", "");
            goodsMapper.put("cargonoC", "");
            goodsMapper.put("processfeeC", "");
            goodsMapper.put("bargaincrC", "currCode");//币制

            TWorksheetGoods tWorksheetGoods = new TWorksheetGoods();
            BeanMapUtill.populate(goodsMapper, goods, tWorksheetGoods);

            tWorksheetGoods.setSerialnoC(i++ + "");
            tWorksheetGoods.setDecType("1");//关
            tWorksheetGoods.setIndx(getLongSeq());
            tWorksheetGoods.setConIndxC(conIndx);

            if (goods.getTotalPrice() != null) {
                tWorksheetGoods.setAmountZ(goods.getTotalPrice().toString());
                tWorksheetGoods.setBargaintoC(goods.getTotalPrice().toString());//成交总价
            }

            tWorksheetGoods.setWorksheetindx(conIndx);
            tWorksheetGoods.setBargaincrcnC(DictTag.getCargoParamVal("S_CURRENCY_E", tWorksheetGoods.getBargaincrC(),
                                                                     "CODE_C",
                                                                     "NAME_C"));//币值中文名称
            tWorksheetGoods.setBargainunnameC(DictTag.getCargoParamVal("S_LAW_UNIT_E", tWorksheetGoods.getBargainunC(),
                                                                       "CODE_C",
                                                                       "NAME_C"));//法定单位中文名称
            tWorksheetGoods.setLegaluncnC(DictTag.getCargoParamVal("S_LAW_UNIT_E", tWorksheetGoods.getLegalunC(),
                                                                   "CODE_C", "NAME_C"));//法定单位中文名称
            tWorksheetGoods.setLevycocnC(DictTag.getCargoParamVal("S_DUTY", tWorksheetGoods.getLevycoC(), "DUTYCO",
                                                                  "DUTYCN"));//征免性质
            tWorksheetGoods.setNationnameC(DictTag.getCargoParamVal("S_COUNTRY", tWorksheetGoods.getNationcoC(),
                                                                    "COUNTRY_CODE",
                                                                    "COUN_C_NAME"));//国家中文名称
            logger.debug("save T_WORKSHEET_GOODS------>{}", tWorksheetGoods);
            commonDao.insert(PREX + "T_WORKSHEET_GOODS", tWorksheetGoods);
            logger.debug("save T_WORKSHEET_GOODS------>end");

            logger.debug("save T_CARGO------>{}", tWorksheetGoods.toTCargo());
            commonDao.insert(PREX + "T_CARGO", tWorksheetGoods.toTCargo());
            logger.debug("save T_CARGO------>end");

        }
    }

    /**
     * 保存集装箱信息列表 到综合表 T_WORKSHEET_CONTAINER  和 T_CONTAINERS 中
     *
     * @param conIndx
     * @param tContainerListQdcs
     */
    private void saveWorksheetContainers(final String conIndx, final List<TContainerListQdc> tContainerListQdcs) {
        if (StringUtils.isEmpty(conIndx)) {
            logger.error("保存集装箱失败，没有对应的表头信息");
            return;
        }
        if (CollectionUtils.isEmpty(tContainerListQdcs)) {
            logger.warn("保存集装箱失败，需要保存的集装箱信息为空");
            return;
        }
        for (TContainerListQdc tContainerListQdc : tContainerListQdcs) {
            TWorksheetContainer tContainers = new TWorksheetContainer();
            tContainers.setIndx(getLongSeq());
            tContainers.setConIndx(conIndx);
            tContainers.setContainno(tContainerListQdc.getContainerId());
            tContainers.setContainty(tContainerListQdc.getContainerMd());
            tContainers.setDecType("1");//关
            tContainers.setContaintyNameC(tContainerListQdc.getContainerMd());
            tContainers.setContaintyC(tContainerListQdc.getContainerId());

            logger.debug("save T_WORKSHEET_CONTAINER------>{}", tContainerListQdc);
            commonDao.insert(PREX + "T_WORKSHEET_CONTAINER", tContainers);
            logger.debug("save T_WORKSHEET_CONTAINER------>end");

            logger.debug("save T_CONTAINERS------>{}", tContainers.toTContainers());
            commonDao.insert(PREX + "T_CONTAINERS", tContainers.toTContainers());
            logger.debug("save T_CONTAINERS------>end");
        }
    }

    /**
     * 保存报关单表头
     *
     * @param declareHead
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    private TEntryInfo saveHead(TDeclformHeadQdc declareHead)
        throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        if (null == declareHead) {
            logger.error("保存表头信息失败，表头信息为空.");
            return null;
        }
        Map<String, String> mapper = new HashMap<>();
        //报关流水号
        mapper.put("entryNo", "");
        //报/转关类型
        mapper.put("dectransid", "");
        mapper.put("dectranscn", "");
        //报关单类型
        mapper.put("custypeco", "");
        mapper.put("custypecn", "");

        //申报地海关
        mapper.put("declarecustomsco", "declPort");
        mapper.put("declarecustoms", "");

        //统一编号
        mapper.put("unientryid", "");

        //预录入编号
        mapper.put("preentryid", "");

        //海关编号
        mapper.put("entryid", "");

        //备案号
        mapper.put("manualno", "");
        //合同协议号
        mapper.put("contractno", "");
        //出口口岸
        mapper.put("portco", "");
        mapper.put("portcn", "");

        //出口日期
        mapper.put("exImDa", "ieDate");
        //申报日期
        mapper.put("declareda", "");
        //经营单位
        mapper.put("operatorid", "tradeCode");
        mapper.put("operatorcn", "tradeName");
        //运输方式
        mapper.put("transportco", "trafMode");
        mapper.put("transportcn", "");
        //发货单位
        mapper.put("ownerco", "");
        mapper.put("ownerna", "");
        //运输工具名称
        mapper.put("conveyance", "trafName");
        //申报单位
        mapper.put("declareid", "agentCode");
        mapper.put("declarecn", "agentName");
        //航次号
        mapper.put("voyageno", "voyageNo");
        //提运单号
        mapper.put("billno", "billNo");
        //监管方式
        mapper.put("tradeco", "");
        mapper.put("tradecn", "");
        //纳税单位
        mapper.put("paytaxco", "");
        mapper.put("paytaxcn", "");
        //许可证号
        mapper.put("licenceno", "");
        //运抵国(地区)
        mapper.put("nationco", "tradeCount");
        mapper.put("nationcocn", "");
        //指运港
        mapper.put("havenco", "");
        mapper.put("havencn", "");
        //成交方式
        mapper.put("tradetermsco", "");
        mapper.put("tradetermscn", "");

        //运费
        mapper.put("carriagesy", "");
        mapper.put("carriagesysy", "");
        mapper.put("carriagesm", "");
        mapper.put("carriagecr", "");
        mapper.put("carriagecrcn", "");

        //征免性质
        mapper.put("dutyco", "");
        mapper.put("dutycn", "");

        //保费
        mapper.put("insurancesy", "");
        mapper.put("insurancesysy", "");
        mapper.put("insurancesm", "");
        mapper.put("insurancecr", "");
        mapper.put("insurancecrcn", "");

        //结汇方式
        mapper.put("paymentco", "");
        mapper.put("paymentcn", "");

        //杂费
        mapper.put("incidentalsy", "");
        mapper.put("incidentalsysy", "");
        mapper.put("incidentalsm", "");
        mapper.put("incidentalcr", "");
        mapper.put("incidentalcrcn", "");

        //件数
        mapper.put("pieces", "packNum");
        //包装种类
        mapper.put("packageco", "");
        mapper.put("packagecn", "");
        //毛重
        mapper.put("gross", "grossWeight");
        //净重
        mapper.put("suttle", "");
        //境内货源地
        mapper.put("regionco", "");
        mapper.put("regioncn", "");
        //备注
        mapper.put("remark", "");

        TEntryInfo entryHead = new TEntryInfo();
        BeanMapUtill.populate(mapper, declareHead, entryHead);

        entryHead.setIndx(getLongSeq());
        entryHead.setConIndx(getELongSeq());
        String ieFlag = declareHead.getIeFlag();
        entryHead.setEntryty(ieFlag);
        entryHead.setTradeco("9610");//电子商务


        String entrytycn = "";
        if ("I".equals(ieFlag)) {
            entrytycn = "进口";
        } else if ("E".equals(ieFlag)) {
            entrytycn = "出口";
        }
        entryHead.setEntrytycn(entrytycn);
        entryHead.setCreatetime(DateUtil.nowTime());

        HttpServletRequest request =
            ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        UserInfo user = SessionUtil.getUserInfo(request.getSession());
        entryHead.setAgentco(user.getCompanyName());
        entryHead.setMaker(user.getLogName());
        entryHead.setStatus("0");
        entryHead.setOrganizationId(user.getOrganizationId());
        entryHead.setOperatorid(user.getLogName());

        logger.debug("save T_ENTRYINFO------>{}", entryHead);
        entryInfoDao.insert(PREX + "T_ENTRYINFO", entryHead);
        logger.debug("save T_ENTRYINFO------>end");
        return entryHead;
    }

    /**
     * 保存货物信息列表
     *
     * @param conIndx
     * @param declarationGoodsList
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    private void saveGoods(String conIndx, List<TGoodsListQdc> declarationGoodsList)
        throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        if (StringUtils.isEmpty(conIndx)) {
            logger.error("保存货物信息失败，没有对应的表头信息");
            return;
        }
        if (CollectionUtils.isEmpty(declarationGoodsList)) {
            logger.warn("保存货物信息失败，需要保存的货物信息为空");
            return;
        }

        for (TGoodsListQdc goods : declarationGoodsList) {
            Map<String, String> goodsMapper = new HashMap<>();

            goodsMapper.put("model", "gModel"); //商品型号
            goodsMapper.put("memo", "");
            goodsMapper.put("cargotaxco", "codeTs");//hscode
            goodsMapper.put("legalsm", "qty1");//法定数量
            goodsMapper.put("menorizesign", "");
            goodsMapper.put("nationname", "");
            goodsMapper.put("bargainto", "totalPrice");//成交总价
            goodsMapper.put("bargainsm", "gNum");//数量
            goodsMapper.put("cargocn", "gName");///商品名称
            goodsMapper.put("quaIndx", "");
            goodsMapper.put("bargaincrcn", "");
            goodsMapper.put("seconduncn", "");
            goodsMapper.put("cargoen", "");
            goodsMapper.put("legalun", "unit1");//法定单位
            goodsMapper.put("legaluncn", "");
            goodsMapper.put("levyco", "dutyMode");//征免方式
            goodsMapper.put("codeT", "");
            goodsMapper.put("codeS", "");
            goodsMapper.put("secondsm", "");
            goodsMapper.put("serialno", "gNo");//序号
            goodsMapper.put("nationco", "originCountry");//原产国/目的国
            goodsMapper.put("manualsn", "");
            goodsMapper.put("purposeco", "");
            goodsMapper.put("secondun", "");
            goodsMapper.put("levycocn", "");
            goodsMapper.put("bargainun", "");
            goodsMapper.put("nationcocn", "");
            goodsMapper.put("bargainunname", "");
            goodsMapper.put("purposecocn", "");
            goodsMapper.put("bargainuncn", "");
            goodsMapper.put("manufacturer", "");
            goodsMapper.put("bargainprice", "price");//单价
            goodsMapper.put("enyIndx", "");
            goodsMapper.put("cargono", "");
            goodsMapper.put("processfee", "");
            goodsMapper.put("bargaincr", "currCode");//币制

            TCargo cargo = new TCargo();
            BeanMapUtill.populate(goodsMapper, goods, cargo);

            cargo.setIndx(getLongSeq());
            cargo.setConIndx(conIndx);
            cargo.setBargainunname(DictTag.getCargoParamVal("S_LAW_UNIT_E", cargo.getBargainun(), "CODE_C", "NAME_C"));
            cargo.setLegaluncn(DictTag.getCargoParamVal("S_LAW_UNIT_E", cargo.getLegalun(), "CODE_C", "NAME_C"));
            cargo.setLevycocn(DictTag.getCargoParamVal("s_Duty", cargo.getLevyco(), "DUTYCO", "DUTYCN"));
            cargo.setNationcocn(DictTag.getCargoParamVal("s_country", cargo.getNationco(), "COUNTRY_CODE",
                                                         "COUN_C_NAME"));
            logger.debug("save T_CARGO------>{}", cargo);
            cargoDao.insert(PREX + "T_CARGO", cargo);
            logger.debug("save T_CARGO------>end");
        }
    }

    /**
     * 保存集装箱信息列表
     *
     * @param conIndx
     * @param tContainerListQdcs
     */
    private void saveContainers(final String conIndx, final List<TContainerListQdc> tContainerListQdcs) {
        if (StringUtils.isEmpty(conIndx)) {
            logger.error("保存集装箱失败，没有对应的表头信息");
            return;
        }
        if (CollectionUtils.isEmpty(tContainerListQdcs)) {
            logger.warn("保存集装箱失败，需要保存的集装箱信息为空");
            return;
        }
        for (TContainerListQdc tContainerListQdc : tContainerListQdcs) {
            TContainers tContainers = new TContainers();
            tContainers.setIndx(getLongSeq());
            tContainers.setConIndx(conIndx);
            tContainers.setContainno(tContainerListQdc.getContainerId());
            tContainers.setContainty(tContainerListQdc.getContainerMd());
            logger.debug("save T_CONTAINERS------>{}", tContainerListQdc);
            tContainerDao.insert(PREX + "T_CONTAINERS", tContainers);
            logger.debug("save T_CONTAINERS------>end");
        }
    }


    /**
     * 更新已经生成报关单的清单，将关联报关单的字段进行赋值
     *
     * @param id
     * @param relateDeclCustId
     */
    public void updateDeclareFormHead(String id, String relateDeclCustId) {
        TDeclformHeadQdc tDeclformHeadQdc = new TDeclformHeadQdc();
        tDeclformHeadQdc.setId(id);
        tDeclformHeadQdc.setRelateDeclCustId(relateDeclCustId);
        qdtDeclareFormHeadDao.update(TableConstants.T_DECLFORM_HEAD_QDC, tDeclformHeadQdc,
                                     "  WHERE ID=#{updateObj.id} ");
    }
}
